package com.bestcem.xm.member.grpc.client;

import cn.hutool.core.util.StrUtil;
import com.bestcem.xm.common.core.constant.GrpcClientNames;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.sql.ConditionException;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.label.constant.Constants;
import com.bestcem.xm.member.grpc.client.dto.CompileConditionDTO;
import com.bestcem.xm.member.grpc.client.dto.ExecuteConditionDTO;
import com.bestcem.xm.member.grpc.client.params.CompileConditionParam;
import com.bestcem.xm.member.grpc.client.params.ExecuteConditionParam;
import com.bestcem.xm.member.service.dto.MemberStatDTO;
import com.bestcem.xm.survey.grpc.v1.services.*;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Component("surveyClient")
public class SurveyClient {

    /**
     * Survey服务存根
     */
    @GrpcClient(GrpcClientNames.DS_SURVEY)
    private BaseSurveyServiceGrpc.BaseSurveyServiceBlockingStub baseStub;

    /**
     * Bp Survey服务存根
     */
    @GrpcClient(GrpcClientNames.DS_SURVEY)
    private BpSurveyServiceGrpc.BpSurveyServiceBlockingStub stub;

    public Respondent getRespondent(String id, String projectId) {
        if (StrUtil.isBlank(id)) {
            return null;
        }

        GetRespondentRequest.Builder builder = GetRespondentRequest.newBuilder();
        builder.setId(id);
        builder.setProjectId(projectId);
        GetRespondentRequest request = builder.build();

        RespondentResponse response = baseStub.getRespondent(request);

        if (response.getStatus().getCodeValue() == Constants.SUCCESS) {
            if (log.isInfoEnabled()) {
                log.info("[XM] 返回：{}", response.getRespondent());
            }
            return response.getRespondent();
        } else {
            if (log.isErrorEnabled()) {
                log.error("[XM] 调用 getRespondent 接口失败: message: {}", response.getStatus());
            }
            return null;
        }
    }

    public ServiceResult<String> updateRespondent(Respondent respondent, String projectId) {
        if (Objects.isNull(respondent)) {
            return ServiceResult.fail("更新问卷不能为空");
        }
        if (Objects.isNull(respondent.getId())) {
            return ServiceResult.fail("更新问卷Id不能为空");
        }

        UpdateRespondentRequest.Builder builder = UpdateRespondentRequest.newBuilder();
        builder.setId(respondent.getId());
        builder.setRespondent(respondent);
        builder.setProjectId(projectId);
        // 更新问卷
        UpdateResponse response = baseStub.updateRespondent(builder.build());
        if (response.getStatus().getCodeValue() != Constants.SUCCESS) {
            log.error("更新问卷失败, response: {}", response);
            return ServiceResult.fail("更新问卷失败");
        }
        return ServiceResult.success(response.getId());
    }

    /**
     * 获取联系人数据指标列表
     *
     * @param memberIds
     * @param orgId
     * @return
     */
    public ServiceResult<Map<String, MemberStatDTO>> listMemberStats(List<String> memberIds, String orgId) {
        if (CollectionUtils.isEmpty(memberIds)) {
            return ServiceResult.success(Collections.emptyMap());
        }

        ListMemberStatsResponse response = stub.listMemberStats(ListMemberStatsRequest.newBuilder()
                .addAllMemberIds(memberIds).setOrgId(orgId).build());
        if (response.getStatus().getCodeValue() != Constants.SUCCESS) {
            log.error("获取联系人数据指标失败, response: {}", response);
            return ServiceResult.fail("获取联系人数据指标失败");
        }

        // 处理返回结果
        List<MemberStat> memberStats = response.getStatsList();
        if (CollectionUtils.isEmpty(memberStats)) {
            return ServiceResult.success(Collections.emptyMap());
        }
        Map<String, MemberStatDTO> memberStatMap = memberStats.stream().map(this::toMemberStatDTO)
                .filter(Objects::nonNull).collect(Collectors.toMap(MemberStatDTO::getMemberId, Function.identity()));
        return ServiceResult.success(memberStatMap);
    }

    /**
     * 编译问卷相关条件
     *
     * @param compileCondition
     * @return
     */
    public CompileConditionDTO compileCondition(String orgId, CompileConditionParam compileCondition) {
        if (compileCondition == null) {
            return null;
        }
        CompileConditionDTO compileConditionDTO = new CompileConditionDTO();
        compileConditionDTO.setConditionId(compileCondition.getConditionId());
        compileConditionDTO.setValid(true);
        return compileConditionDTO;
    }

    /**
     * 编译问卷相关条件
     *
     * @param orgId
     * @param compileConditions
     * @return
     */
    public List<CompileConditionDTO> compileConditions(String orgId, List<CompileConditionParam> compileConditions) {
        // 参数检查
        if (StringUtils.isBlank(orgId)) {
            throw new IllegalArgumentException("param orgId missing");
        }
        if (CollectionUtils.isEmpty(compileConditions)) {
            return Collections.emptyList();
        }

        return compileConditions.stream()
                .map(compileCondition -> new CompileConditionDTO(compileCondition.getConditionId(), true))
                .collect(Collectors.toList());
    }

    /**
     * 解释执行问卷相关条件
     *
     * @param executeConditions
     * @return
     */
    public List<ExecuteConditionDTO> executeConditions(List<ExecuteConditionParam> executeConditions) {
        // 验证参数
        if (CollectionUtils.isEmpty(executeConditions)) {
            return Collections.emptyList();
        }

        // 构建请求
        ExecuteConditionsRequest.Builder builder = ExecuteConditionsRequest.newBuilder();
        executeConditions.stream().map(GRpcUtil::fillDefaultValue)
                .forEach(executeCondition -> builder.addConditions(ExecuteCondition.newBuilder()
                        .setOrgId(executeCondition.getOrgId())
                        .setConditionId(executeCondition.getConditionId())
                        .setProjectId(executeCondition.getProjectId())
                        .setMemberId(executeCondition.getMemberId())
                        .setCondition(executeCondition.getCondition())
                        .build()));
        ExecuteConditionsRequest request = builder.build();
        if (log.isDebugEnabled()) {
            log.debug("request: {}", GRpcUtil.serialize(request));
        }
        ExecuteConditionsResponse response = stub.executeConditions(request);
        if (response.getStatus().getCodeValue() != Constants.SUCCESS) {
            log.error("execute conditions failed, response: {}", GRpcUtil.serialize(response));
            throw new ConditionException("execute conditions failed");
        }

        // 处理结果
        List<ExecuteConditionResult> results = response.getResultsList();
        if (CollectionUtils.isEmpty(results)) {
            return Collections.emptyList();
        }
        return results.stream()
                .map(result -> ExecuteConditionDTO.builder()
                        .conditionId(result.getConditionId())
                        .memberId(result.getMemberId())
                        .match(result.getMatchValue())
                        .build())
                .collect(Collectors.toList());
    }

    /**
     * 类型转换
     *
     * @param memberStat
     * @return
     */
    private MemberStatDTO toMemberStatDTO(MemberStat memberStat) {
        if (memberStat == null) {
            return null;
        }

        MemberStatDTO memberStatDTO = new MemberStatDTO();
        memberStatDTO.setMemberId(memberStat.getMemberId());
        memberStatDTO.setAnswerRate(memberStat.getAnswerRate());
        memberStatDTO.setSubmitRate(memberStat.getSubmitRate());
        memberStatDTO.setStartAnswerCount(memberStat.getStartAnswerCount());
        memberStatDTO.setReceiveDeliverCount(memberStat.getReceiveDeliverCount());
        return memberStatDTO;
    }
}
